package com.baixun.gassystem.filter;

import com.baixun.gascommon.annotation.DataPermission;
import com.baixun.gascommon.utils.RedisUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * @program: 上海燃气驾驶舱
 * @description: 实现 AOP 切面逻辑，当方法被 @DataPermission 注解标记时，切面会拦截方法调用，从 Redis 中加载权限数据并进行结果过滤。
 * @author: yesong
 **/

@Aspect
@Component
public class DataPermissionAspect {

    @Autowired
    private RedisUtils redisUtils;

    // 拦截标记了 @DataPermission 的方法
    @AfterReturning(pointcut = "@annotation(dataPermission)", returning = "result")
    public void applyDataPermission(JoinPoint joinPoint, DataPermission dataPermission, Object result){
        //从方法参数种获取userId
        Object[] args = joinPoint.getArgs();
        Long userId = (Long) args[0];

        //从redis种获取allowedIds
        List<Long> allowedIds = getAllowedIdsFromRedis(userId);

        //如果allowedIds为空，则直接抛出异常
        if(CollectionUtils.isEmpty(allowedIds)){
            throw new RuntimeException("用户没有权限");
        }

        //根据allowedIds过滤查询结果
        filterResultsByPermissions(result, allowedIds, dataPermission.field());

    }

    private List<Long> getAllowedIdsFromRedis(Long userId){
        String permissionKey = "permissios:"+userId;
        return redisUtils.getList(permissionKey, Long.class);
    }

    private void filterResultsByPermissions(Object result,List<Long> allowedIds, String field){
        // 依据 allowedIds 过滤查询结果
        if (result instanceof List){
            List<?> resultList= (List<?>) result;
            resultList.removeIf(item-> !allowedIds.contains(getFieldValue(item,field)));
        }
    }

    private Object getFieldValue(Object item,String fieldName){
        try {
            Field field = item.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(item);
        } catch (Exception e) {
            throw new RuntimeException("权限过滤失败，无法访问字段: " + fieldName, e);
        }
    }

    private  void clearResult(Object result){
        if (result instanceof List){
            ((List<?>) result).clear();
        }
    }

}

